package middleware.p2p.global.logger;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.Iterator;
import java.util.LinkedList;

import javax.ejb.Singleton;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;

import middleware.p2p.log.MiddlewareLogEvent;
import middleware.p2p.log.VectorClock;

/**
 * Session Bean implementation class EventQueueManager
 */
@Singleton(name="LogQueue")
@TransactionManagement(TransactionManagementType.BEAN)
public class EventQueueManager implements EventQueueManagerLocal {
	private LinkedList<MiddlewareLogEvent> incoming;
	private VectorClock vclock;
	/*private Timer intervalTime=null;
	@Resource	
	private TimerService timerService;*/
    /**
     * Default constructor. 
     */
    public EventQueueManager() {
    	super();
    	this.vclock=new VectorClock();
    	this.incoming=new LinkedList<MiddlewareLogEvent>();
    }

    private void deliver(MiddlewareLogEvent event) {
    	Iterator<String> keyIt=event.getVclock().getAllKey().iterator();
    	while (keyIt.hasNext()) {
    		String cKey=keyIt.next();
    		int currValue=this.vclock.getClock(cKey);
    		int remValue=event.getVclock().getClock(cKey);
    		if (remValue>currValue) {
    			this.vclock.setClock(cKey, remValue);
    		} else if((currValue==0)&&(remValue==0)) {
    			this.vclock.setClock(cKey, 0);
    		}
    	}
    	//System.out.println(event.getVclock());
    	File globalLog=new File(".."+File.separator+"logs"+File.separator+"middleware_global_log.log");
		try {
			PrintStream outFile = new PrintStream(new FileOutputStream(globalLog, true));
	    	outFile.println(event.toXmlString());
	    	outFile.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
    }
    private boolean deliverCompare(MiddlewareLogEvent right) {
    	int comp=vclock.compareTo(right.getVclock());
		boolean gapDetect=vclock.detectGap(right.getVclock());
		boolean proxDetect=vclock.detectProximity(right.getVclock());
		//System.out.println("COMPARE=>"+comp+" || GAP =>"+gapDetect+" || PROX =>"+proxDetect);
		//System.out.println("$$$$$$$$$$$$$$$$$$$$$$$"+vclock.toString()+"\n********************"+right.getVclock().toString());
		if ((comp==-1)&&(!gapDetect)&&(proxDetect)) {
			return true;
		} else if((comp==0)&&(proxDetect)) {
			return true;
		} else {
			return false;
		}
    }
	@Override
	public boolean enqueue(MiddlewareLogEvent event) {
		try{
			if (deliverCompare(event)) {
				//System.out.println("========>immediate delivery \n");
				deliver(event);
				boolean found=true;
				while (found) {
					Iterator<MiddlewareLogEvent> itEv=this.incoming.iterator();
					found=false;
					while (itEv.hasNext()) {
						MiddlewareLogEvent currEvent=itEv.next();
						if (deliverCompare(currEvent)) {
							itEv.remove();
							deliver(currEvent);
							found=true;
							break;
						}
					}
				}
			} else {
				incoming.add(event);
			}
			return true;
		}
		catch(IllegalStateException e){
			e.printStackTrace();
			return false;
		}
	}

	@Override
	public boolean resetQueue(String cid) {
		//System.out.println("Reset Clock "+cid);
		this.vclock.setClock(cid, 0);
		return true;
	}	
}
